package com.adwyxx.reflection;

import java.lang.reflect.*;

/**
 * Class:
 * <p>Class对象是反射的源头，每个类都有一个Class对象，每个Class对象都对应一个类，每个类只有一个Class对象:</p>
 * - Class本身也是一个类;
 * - Class 对象只能由系统建立对象;
 * - 一个加载的类在 JVM 中只会有一个Class实例;
 * - 一个Class对象对应的是一个加载到JVM中的一个.class文件;
 * - 每个类的实例都会记得自己是由哪个Class 实例所生成;
 * - 通过Class可以完整地得到一个类中的所有被加载的结构;
 * - Class类是Reflection的根源，针对任何你想动态加载、运行的类，唯有先获得相应的Class对象;
 * <p>
 * 获取Class对象的方式:
 * - 若已知具体的类，通过类的class属性获取，该方法最为安全可靠，程序性能最高
 * - 若已知某个类的实例，调用实例的getClass()方法获取Class对象
 * - 若已知一个类的全类名，且该类在类路径下，可通过Class类的静态方法forName()获取
 * - 通过ClassLoader实现类的加载
 *
 * @author Leo.W
 * @date 2024-09-06 9:28
 */
public class ClassDemo {
    static class User<T> {
        private String name;
        private T arg;
        public User() {
        }

        public User(String name,T arg) {
            this.name = name;
            this.arg = arg;
        }
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return String.format("{name:%s}", name);
        }
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {

        // 方式一:通过类的class属性获取Class对象
        Class<User> class1 = User.class;
        System.out.println(class1.getName()); // com.adwyxx.reflection.ClassDemo$User

        // 方式二:通过实例的getClass()方法获取Class对象
        User user = new User();
        Class<? extends User> class2 = user.getClass();
        System.out.println(class2.getName()); // com.adwyxx.reflection.ClassDemo$User

        // 方式三:通过Class类的静态方法forName()获取Class对象
        // 注意：ClassDemo 的内部类 User 要是用 ClassDemo$User 而不是 ClassDemo.User
        Class<?> class3 = Class.forName("com.adwyxx.reflection.ClassDemo$User");
        System.out.println(class3.getName()); // com.adwyxx.reflection.ClassDemo$User

        // 方式四:通过ClassLoader实现类的加载
        Class<?> class4 = ClassDemo.class.getClassLoader().loadClass("com.adwyxx.reflection.ClassDemo$User");
        System.out.println(class4.getName()); // com.adwyxx.reflection.ClassDemo$User

        // 获取类加载器
        System.out.println("类加载器 --> "+class4.getClassLoader());
        // 获取父类
        System.out.println("父类 --> "+class4.getSuperclass());
        // 获取接口
        System.out.println("---------- 接口 ----------");
        for (Class<?> anInterface : class4.getInterfaces()) {
            System.out.println(anInterface);
        }
        // 获取所有属性字段
        // getFields(); 获取所有公共属性字段,包含父类继承的属性
        // getDeclaredFields(); 获取所有属性字段，包含私有属性
        System.out.println("---------- 字段 ----------");
        for (Field field : class4.getDeclaredFields()) {
            System.out.println(field);
        }
        // 获取所有方法
        // getMethods(); 获取所有方法,包含父类继承的方法
        // getDeclaredMethods(); 获取自身定义的方法(包含 @Override 的方法)，不包含父类方法
        System.out.println("---------- 方法 ----------");
        for (Method method : class4.getDeclaredMethods()) {
            System.out.println(method);
        }

        // 获取构造方法
        System.out.println("---------- 构造方法 ----------");
        for (Constructor constructor : class4.getConstructors()) {
            System.out.println(constructor);
            if(constructor.getParameterCount()>0){
                System.out.println("--- 参数 :");
                Parameter[] parameters = constructor.getParameters();
                for (Parameter parameter : parameters) {
                    System.out.println(parameter.getName()+" -> "+parameter.getType());
                }
                User<String> user2 = (User<String>)constructor.newInstance("张三","abc");
                System.out.println(user2);
            }
        }

        // 获取泛型类型
        System.out.println("---------- 泛型类型 ----------");
        for (TypeVariable type : class4.getTypeParameters()) {
            System.out.println(type);
        }

        // 创建一个实例对象
       User<String> user1 = (User<String>) class4.newInstance();
    }
}
